package define

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"github.com/kballard/go-shellquote"
	"io/ioutil"
	"net/http"
	"os/exec"
	"strconv"
	"xlib/log"

	"github.com/gin-gonic/gin"
)

//MD5 MD5
func MD5(src string) string {
	data := []byte(src)
	h := md5.Sum(data)
	return fmt.Sprintf("%x", h)
}

// 字节的单位转换 保留两位小数
func FormatFileSize(fileSize int64) (size string) {
	if fileSize < 1024 {
		return fmt.Sprintf("%.2fB", float64(fileSize)/float64(1))
	} else if fileSize < (1024 * 1024) {
		return fmt.Sprintf("%.2fKB", float64(fileSize)/float64(1024))
	} else if fileSize < (1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fMB", float64(fileSize)/float64(1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fGB", float64(fileSize)/float64(1024*1024*1024))
	} else if fileSize < (1024 * 1024 * 1024 * 1024 * 1024) {
		return fmt.Sprintf("%.2fTB", float64(fileSize)/float64(1024*1024*1024*1024))
	} else {
		return fmt.Sprintf("%.2fEB", float64(fileSize)/float64(1024*1024*1024*1024*1024))
	}
}

//QueryString 获取字符串
func QueryString(c *gin.Context, key string) (string, error) {
	var param string

	if param = c.Query(key); param == "" {
		ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamMissing, EmParamMissing, key)
		return param, fmt.Errorf("%s: %s", EmParamMissing, key)
	}

	return param, nil
}

//QueryInt 获取字符串
func QueryInt(c *gin.Context, key string) (int, error) {
	var (
		p     string
		param int
		err   error
	)

	if p = c.Query(key); p == "" {
		ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamMissing, EmParamMissing, key)
		return 0, fmt.Errorf("%s: %s", EmParamMissing, key)
	}

	if param, err = strconv.Atoi(p); err != nil {
		ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamFormat, EmParamFormat, err.Error())
		return 0, fmt.Errorf("parameter parsing error, %s: %s. ERR: %s", key, p, err.Error())
	}

	return param, nil
}

//ParseParam POST参数解析
func ParseParam(c *gin.Context, key string, param interface{}) error {
	switch c.ContentType() {
	case URLEncoded:
		var p string

		if p = c.PostForm(key); p == "" {
			ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamMissing, EmParamMissing, key)
			return fmt.Errorf("%s: %s", EmParamMissing, key)
		}

		if err := json.Unmarshal([]byte(p), param); err != nil {
			ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamFormat, EmParamFormat, err.Error())
			return fmt.Errorf("parameter parsing error: %s. ERR: %s", p, err.Error())
		}
	case Json:
		if err := c.BindJSON(param); err != nil {
			ErrorCodeWithExtraInfo(c, http.StatusOK, EcParamFormat, EmParamFormat, err.Error())
			return fmt.Errorf("parameter parsing error. ERR: %s", err.Error())
		}
	}

	return nil
}

//SuccessWithData 成功
func SuccessWithData(c *gin.Context, httpCode int, data interface{}) {
	c.JSON(httpCode, Response{
		ErrCode: EcSuccess,
		ErrMsg:  EmSuccess,
		Data:    data,
	})
}

//ErrorCodeWithMsg 失败
func ErrorCodeWithMsg(c *gin.Context, httpCode int, errCode int, errMsg string) {
	c.JSON(httpCode, Response{
		ErrCode: errCode,
		ErrMsg:  errMsg,
	})
}

//ErrorCodeWithExtraInfo 失败
func ErrorCodeWithExtraInfo(c *gin.Context, httpCode int, errCode int, errMsg, extraInfo string) {
	c.JSON(httpCode, Response{
		ErrCode: errCode,
		ErrMsg:  fmt.Sprintf("%s: %s", errMsg, extraInfo),
	})
}

// CmdCommand 执行cmd命令
func CmdCommand(cmd string) (string, error) {
	log.Debugf("执行了 %s", cmd)
	cmdList, _ := shellquote.Split(cmd)
	f := exec.Command(cmdList[0], cmdList[1:]...)
	stdOut, err := f.StdoutPipe()
	if err != nil {
		log.Errorf("创建标准输出管道失败：%+v", err)
		return "", err
	}
	defer stdOut.Close()
	err = f.Start()
	if err != nil {
		log.Errorf("f.Start() error:%s", err.Error())
		return "", err
	}
	r, err := ioutil.ReadAll(stdOut)
	if err != nil {
		log.Errorf("从管道中读取数据失败：%+v", err)
		return "", err
	}
	if len(r) > 1 && r[len(r)-1] == byte(10) {
		r = r[:len(r)-1]
	}
	err = f.Wait()
	if err != nil {
		log.Errorf("f.Wait() error:%s,  %s", err.Error(), string(r))
		return string(r), err
	}
	return string(r), nil
}
